package pool;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import pool.errors.ClientQueue;
import pool.errors.ErrorHandler;
import pool.errors.ExceptionHandlerType;
import pool.errors.QueueHandlerType;
import pool.exceptions.EmptyPoolException;
import pool.model.DefaultThread;
import pool.model.IThread;
import pool.properties.MyProperties;
import pool.test.client.Client;

public class ThreadPool {

	private List<IThread> allThread;
	private int poolSize;
	private String handlerType;
	private MyProperties myProperties;

	private List<ErrorHandler> handlers;

	/* Implemented as Singleton */
	private static ThreadPool instance = null;

	/** default constructor */
	private ThreadPool() {
		init();
	}

	/** create instance */
	public synchronized static ThreadPool getInstance() {
		if (instance == null) {
			instance = new ThreadPool();
		}
		return instance;
		
		
	}
	

	public IThread getThread(Client c) throws EmptyPoolException {

		IThread thread = null;

		for (IThread ith : allThread) {
			if (ith.isInUse() == false) {
				ith.setInUse(true);
				thread = ith;
				break;
			}
		}

		if(thread == null){
			handleException(c);
		}
		return thread;
	}

	public void releaseThread(IThread thread) {
		thread.setInUse(false);
		System.out.println(thread + " released! " );
		
		handlers.get(0).event(handlerType);
	}

	
	private void handleException(Client client) throws EmptyPoolException {

			handlers.get(0).handle(handlerType, client);

	}

	/** custom handler can be added.. */
	public void addHandler(ErrorHandler handler) {
		handlers.add(handler);
	}

	/** initialize class */
	private void init() {

		allThread = Collections.synchronizedList(new ArrayList<IThread>());
		myProperties = new MyProperties("config");

		// init handlers
		handlers = new ArrayList<ErrorHandler>();
		ErrorHandler exceptionHandler = new ExceptionHandlerType();
		ErrorHandler queueHandler = new QueueHandlerType();
		handlers.add(exceptionHandler);
		handlers.add(queueHandler);
		
		// set successors
		for (int i = 0, j = 1; i < handlers.size() - 1; i++) {
			handlers.get(i).setNext(handlers.get(j));
			j++;
		}

		poolSize = Integer.parseInt(myProperties.getProperty("pool.size"));
		handlerType = myProperties.getProperty("handler.type");


		// initialize pool
		for (int i = 0; i < poolSize; i++) {
			DefaultThread defaultThread = new DefaultThread(i);
			// defaultThread.start();

			allThread.add(defaultThread);
		}
	}

}